/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fr.utbm.tx52.stamp.ui.fragment;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;
import fr.utbm.tx52.stamp.ui.activity.Viewer;

/**
 *
 * @author Nathan
 */
public class ZoomImageView extends ImageView {
    private static final int INVALID_POINTER_ID = -1;
    
    private float mPosX;
    private float mPosY;
    
    private float downTouchX;
    private float downTouchY;
    
    private float mLastTouchX;
    private float mLastTouchY;
    private int mActivePointerId = INVALID_POINTER_ID;
    
    private ScaleGestureDetector mScaleDetector;
    private float mScaleFactor = 1.f;
    
    public ZoomImageView(Context context) {
        this(context, null, 0);
    }
    
    public ZoomImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    
    public ZoomImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // Let the ScaleGestureDetector inspect all events.
        mScaleDetector.onTouchEvent(ev);
        
        final int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                final float x = ev.getX();
                final float y = ev.getY();
                downTouchX = mLastTouchX = x;
                downTouchY = mLastTouchY = y;
                mActivePointerId = ev.getPointerId(0);
                break;
            }

            case MotionEvent.ACTION_MOVE: {
                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                final float x = ev.getX(pointerIndex);
                final float y = ev.getY(pointerIndex);

                // Only move if the ScaleGestureDetector isn't processing a gesture.
                if (!mScaleDetector.isInProgress()) {
                    final float dx = x - mLastTouchX;
                    final float dy = y - mLastTouchY;

                    mPosX += dx;
                    mPosY += dy;
                                        
                    invalidate();
                }

                mLastTouchX = x;
                mLastTouchY = y;

                break;
            }

            case MotionEvent.ACTION_UP: {
                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                final float x = ev.getX(pointerIndex);
                final float y = ev.getY(pointerIndex);
                // Si a la fin de la gesture le positionnement du doigt n'a pas bougé, on affiche la vue d'overlay dans Viewer.java
                if(downTouchX == x && downTouchY == y){
                    try{
                        ((Viewer)this.getContext()).setOverlayVisible();
                    }
                    catch(Exception e){}
                }
                        
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_CANCEL: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_POINTER_UP: {
                final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = ev.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mLastTouchX = ev.getX(newPointerIndex);
                    mLastTouchY = ev.getY(newPointerIndex);
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                }
                break;
            }
        }
        
        return true;
    }

    /** Methode pour corriger le positionnement lors du zoom/dezoom
     * Defaut de fonctionnement avec une image avec un ratio (Width/Height) inferieur a celui de l'imageView
     */
    public void correctPositionning(){
        // Hauteur lorsque la largeur est égale à celle de l'écran
        int modHeight = (int)(((float)((float)this.getDrawable().getIntrinsicHeight() / (float)this.getDrawable().getIntrinsicWidth())) * (float)this.getWidth());
        
        // Si l'image est trop à droite on la replace au bord
        if(mPosX > 0)
            mPosX = 0;
        // Sinon si l'image est trop à gauche on la replace au bord
        else if( mPosX + this.getWidth()*mScaleFactor < this.getWidth()){
            mPosX = this.getWidth() - this.getWidth()*mScaleFactor;
        }
        // Si la hauteur actuelle de l'image est inférieure à la hauteur de l'écran on place au milieu (en hauteur)
        if(modHeight*mScaleFactor <= this.getHeight()){
            mPosY = 0 - (this.getHeight()*mScaleFactor - this.getHeight())/2;
        }
        // Sinon on empeche l'image de sortir de l'écran
        else{
            // Si l'image est trop basse on la replace au bord
            if(mPosY > 0-(this.getHeight()-modHeight)/2 * mScaleFactor )
                mPosY = 0-(this.getHeight()-modHeight)/2 * mScaleFactor;
            // Sinon si elle est trop haute on la replace au bord
            if( mPosY + this.getHeight()*mScaleFactor < this.getHeight() + (this.getHeight()-modHeight)/2 * mScaleFactor){
                mPosY = this.getHeight() + (this.getHeight()-modHeight)/2 * mScaleFactor - this.getHeight()*mScaleFactor;
            }
        }
    }
    
    @Override
    public void onDraw(Canvas canvas) {
        this.correctPositionning(); // correction du positionnement
        canvas.save();
        canvas.translate(mPosX, mPosY); // deplacement de l'imageView
        canvas.scale(mScaleFactor, mScaleFactor); // mise à jour du zoom
        super.onDraw(canvas);
        canvas.restore();// restauration des propriétés du canva lors du save();
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();
            
            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(1, Math.min(mScaleFactor, 5.0f));

            invalidate();
            return true;
        }
    }
}